import React from 'react';
import { View } from './View';
import { PropertyEditor } from './PropertyEditor';
import { DataSource } from '../services/DataSource';
import { 
  StringPropertyEditor,
  NumberPropertyEditor,
  BooleanPropertyEditor,
  DatePropertyEditor,
  DropDownPropertyEditor
} from '../components/PropertyEditors';

/**
 * DetailView class - Displays a single record with all its properties.
 */
export class DetailView extends View {
  private _object: any = null;
  private _propertyEditors: PropertyEditor[] = [];
  private _dataSource: DataSource | null = null;
  private _relatedViews: { [key: string]: View } = {};
  private _isEditing: boolean = false;
  private _validationErrors: { [key: string]: string } = {};

  /**
   * Create a new DetailView
   * @param id View identifier
   * @param caption View caption
   * @param dataSource Optional data source for this view
   */
  constructor(id: string, caption: string, dataSource?: DataSource) {
    super(id, caption);
    this._dataSource = dataSource || null;
  }

  /**
   * Render method implementation for View abstract class
   */
  public render(): JSX.Element | null {
    // The actual rendering is handled by the DetailView React component
    return null;
  }

  /**
   * Get the current object being displayed
   */
  public get currentObject(): any {
    return this._object;
  }

  /**
   * Get validation errors
   */
  public get validationErrors(): { [key: string]: string } {
    return { ...this._validationErrors };
  }

  /**
   * Get whether there are any validation errors
   */
  public get hasValidationErrors(): boolean {
    return Object.keys(this._validationErrors).length > 0;
  }

  /**
   * Validate all property editors
   */
  public validateAllEditors(): boolean {
    this._validationErrors = {};

    // Validate each property editor
    for (const editor of this._propertyEditors) {
      const value = this._object[editor.propertyName];
      const validation = editor.render(value, () => {}).error;
      
      if (validation) {
        this._validationErrors[editor.propertyName] = validation;
      }
    }

    return !this.hasValidationErrors;
  }
  /**
   * Set the object to display in this detail view
   * @param obj The object to display
   */
  public setObject(obj: any): void {
    // Clear validation errors when setting a new object
    this._validationErrors = {};

    // Make sure obj is either null or an object
    if (obj !== null && typeof obj !== 'object') {
      throw new Error('Invalid object provided to DetailView');
    }

    // If the object is not null and we have a data source, ensure _type is set
    if (obj && this._dataSource && !obj._type) {
      obj._type = this._dataSource.objectTypeName;
    }

    this._object = obj;
  }

  /**
   * Add a property editor to this detail view
   * @param editor The property editor to add
   */
  public addPropertyEditor(editor: PropertyEditor): void {
    if (!this._propertyEditors.includes(editor)) {
      this._propertyEditors.push(editor);
    }
  }

  /**
   * Add a property editor by name, caption, and type
   * @param propertyName The name of the property
   * @param caption The display caption for the property
   * @param type The data type of the property
   * @param isReadOnly Whether the property is read-only
   * @param isRequired Whether the property is required
   */
  public addPropertyEditorByInfo(propertyName: string, caption: string, type: string, isReadOnly: boolean = false, isRequired: boolean = false): void {
    // Create the appropriate property editor based on type
    let editor;
    
    switch (type.toLowerCase()) {
      case 'string':
        editor = new StringPropertyEditor(propertyName, caption);
        break;
      case 'number':
      case 'integer':
      case 'decimal':
        editor = new NumberPropertyEditor(propertyName, caption);
        break;
      case 'boolean':
        editor = new BooleanPropertyEditor(propertyName, caption);
        break;
      case 'date':
      case 'datetime':
        editor = new DatePropertyEditor(propertyName, caption);
        break;
      case 'enum':
      case 'lookup':
        editor = new DropDownPropertyEditor(propertyName, caption);
        break;
      default:
        editor = new StringPropertyEditor(propertyName, caption);
        break;
    }
    
    editor.readOnly = isReadOnly;
    editor.isRequired = isRequired;
    
    this.addPropertyEditor(editor);
  }

  /**
   * Get all property editors in this detail view
   */
  public get propertyEditors(): PropertyEditor[] {
    return [...this._propertyEditors];
  }

  /**
   * Find a property editor by property name
   * @param propertyName The name of the property
   */
  public getEditorByPropertyName(propertyName: string): PropertyEditor | null {
    for (const editor of this._propertyEditors) {
      if (editor.propertyName === propertyName) {
        return editor;
      }
    }
    return null;
  }

  /**
   * Get the data source for this detail view
   */
  public get dataSource(): DataSource | null {
    return this._dataSource;
  }

  /**
   * Set the data source for this detail view
   */
  public set dataSource(value: DataSource | null) {
    this._dataSource = value;
  }

  /**
   * Add a related view
   * @param key The key for the related view (association name)
   * @param view The related view
   */
  public addRelatedView(key: string, view: View): void {
    this._relatedViews[key] = view;
  }

  /**
   * Get all related views
   */
  public get relatedViews(): { [key: string]: View } {
    return { ...this._relatedViews };
  }

  /**
   * Get whether the view is in edit mode
   */
  public get isEditing(): boolean {
    return this._isEditing;
  }

  /**
   * Set whether the view is in edit mode
   */
  public set isEditing(value: boolean) {
    this._isEditing = value;
  }
}
